/*
 * tcpcilent.c
 *
 *  Created on:
 *      Author: dell
 */

#include "tcpclient.h"

#include "bsp_relay.h"
#include "bsp_led.h"
#include "mqtt.h"
#include "bsp_gps.h"
struct espconn tcpcilent_esp_conn;                        //建立一个espconn结构体
esp_tcp tcpcilent_esptcp;                                 //建立一个esp_tcp结构体

char ServerIP[128];                                       //用于保存域名的缓冲区
ip_addr_t Aliyun_ip;                                      //用于保存解析后的阿里云服务器的ip地址
#define SERVRT_PORT           1883                        //阿里云服务器端口号

LOCAL os_timer_t dns_timer;                               //定义一个定时器结构
LOCAL os_timer_t ping_timer;                              //定义一个定时器结构

unsigned char TxData_Buff[512];                           //发送缓冲区
unsigned char MQTT_STA = 0;                               //状态
/*-------------------------------------------------------------*/
/*函数功能：解析阿里云服务器的域名                                                                                 */
/*参       数: 无                                                                                                                                       */
/*返       回：无                                                                                                                                       */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR DNS_Aliyun(void)
{
	tcpcilent_esp_conn.type = ESPCONN_TCP;                   //espconn的类型是TCP
	tcpcilent_esp_conn.state = ESPCONN_NONE;                 //状态，初始的时候是空
	tcpcilent_esp_conn.proto.tcp = &tcpcilent_esptcp;        //因为是TCP类型，所以指向esptcp结构体

	os_memset(ServerIP,128,0);
	os_sprintf(ServerIP,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",PRODUCTKEY);               //构建服务器域名
	espconn_gethostbyname(&tcpcilent_esp_conn, ServerIP, &Aliyun_ip, Aliyun_dns_found);      //启动dns解析，设置回调函数

	os_timer_setfn(&dns_timer, (os_timer_func_t *)Aliyun_dns_check_cb, &tcpcilent_esp_conn);  //设置dns解析定时器
    os_timer_arm(&dns_timer, 1000, 0);                                                        //1s定时器
}
/*-------------------------------------------------------------*/
/*函数功能：域名解析定时器的回调函数                                                              */
/*参       数: arg:传进来的参数                                                                            */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
LOCAL void ICACHE_FLASH_ATTR Aliyun_dns_check_cb(void *arg)
{
    struct espconn *pespconn = arg;

    espconn_gethostbyname(&tcpcilent_esp_conn, ServerIP, &Aliyun_ip, Aliyun_dns_found);      //启动dns解析，设置回调函数
    os_timer_arm(&dns_timer, 1000, 0);                                                       //重新1s定时器启动
}
/*-------------------------------------------------------------*/
/*函数功能：域名解析成功的回调函数                                                                  */
/*参       数: name:域名                                                                                       */
/*参       数: ipaddr:解析后的ip                                    */
/*参       数: arg:指向  espconn结构的指针                                                       */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
LOCAL void ICACHE_FLASH_ATTR Aliyun_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{
    struct espconn *pespconn = (struct espconn *)arg;

    if (ipaddr == NULL) //如果ip等于空，解析未能成功
    {
        os_printf("Aliyun_dns_found NULL \r\n");   //串口提示
        return;   //返回
    }
    else   //该分支表示成功解析到ip
    {
    	os_printf("Aliyun_dns_found %d.%d.%d.%d \r\n",*((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1),*((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3));    //串口打印解析到的ip
    	os_timer_disarm(&dns_timer);     //取消掉dns解析的定时器
    	Aliyun_ip.addr = ipaddr->addr;   //记录ip地址
    	AliIoT_Parameter_Init();         //初始化阿里云参数
		Aliyun_client_init();             //初始化连接阿里云的客户端
    }
}
/*-------------------------------------------------------------*/
/*函数功能：初始化连接阿里云的客户端                                                           */
/*参       数：无                                                                                                     */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR Aliyun_client_init(void)
{
	os_memcpy(tcpcilent_esp_conn.proto.tcp->remote_ip, &Aliyun_ip, 4);         //拷贝服务器ip
	tcpcilent_esp_conn.proto.tcp->remote_port = SERVRT_PORT;                   //拷贝服务器端口号
	tcpcilent_esp_conn.proto.tcp->local_port = espconn_port();                 //自动获取可用的本地端口号

	espconn_regist_connectcb(&tcpcilent_esp_conn, tcp_cilent_connect_cb);     //注册连接成功后的回调函数
	espconn_regist_reconcb(&tcpcilent_esp_conn, tcp_client_recon_cb);         //注册连接异常断开的回调函数
	espconn_connect(&tcpcilent_esp_conn);                                     //连接服务器
}
/*-------------------------------------------------------------*/
/*函数功能：连接成功后的回调函数                                                                     */
/*参       数：arg：指向espconn的指针                                                                 */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR tcp_cilent_connect_cb(void *arg)
{
    struct espconn *pespconn = arg;
    int len;

    LED3_ON;                                                //点亮LED3，表示连接到服务器
    os_printf("connect server!!!\r\n");                     //提示连接服务器成功
    os_timer_disarm(&ping_timer);                           //取消ping定时器
    espconn_regist_recvcb(pespconn, tcp_client_recv_cb);    //注册接收回调函数
    espconn_regist_disconcb(pespconn, tcp_cilent_discon_cb);//注册连接断开回调函数
    len = MQTT_ConectPack(TxData_Buff);                     //构建连接报文
    espconn_sent(pespconn, TxData_Buff, len);               //发送报文
}
/*-------------------------------------------------------------*/
/*函数功能：连接正常断开的回调函数                                                                   */
/*参       数：arg：指向espconn的指针                                                                 */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR tcp_cilent_discon_cb(void *arg)
{
	struct espconn *pespconn = arg;

	LED3_OFF;                                //熄灭LED3
	os_printf("disconnect server!!!\r\n");   //提示连接断开
	os_timer_disarm(&ping_timer);            //取消ping定时器
	espconn_connect(pespconn);               //重新连接服务器
}
/*-------------------------------------------------------------*/
/*函数功能：连接异常断开的回调函数                                                                                 */
/*参       数：arg：指向espconn的指针                                                                 */
/*参       数：err：错误代码                                                                                  */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR tcp_client_recon_cb(void *arg, sint8 err)
{
	struct espconn *pespconn = arg;

	LED3_OFF;                                                      //熄灭LED3
	os_printf("Connection aborted, error code:%d !!! \r\n",err);   //提示连接是异常断开的
	os_timer_disarm(&ping_timer);                                  //取消ping定时器
	espconn_connect(pespconn);                                     //重新连接服务器
}
/*-------------------------------------------------------------*/
/*函数功能：接收到数据的回调函数                                                                      */
/*参       数：arg：指向espconn的指针                                                                */
/*参       数：pusrdata：收到的数据                                                                    */
/*参       数：length：数据量                                                                               */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR tcp_client_recv_cb(void *arg, char *pusrdata, unsigned short length)
{
	struct espconn *pespconn = arg;
	int len;

	os_printf("receive %d byte data:0x%x\r\n", length,pusrdata[0]);    //串口提示数据

	//if判断，如果第一个字节是0x20，表示收到的是CONNACK报文
	//接着我们要判断第4个字节，看看CONNECT报文是否成功
	if(pusrdata[0]==0x20){
		if(pusrdata[3]==0x00){		               //判断第4个字节，等于表示正确
			os_printf("CONNECT Succeeded\r\n");    //串口输出信息
			MQTT_STA = 1;                          //状态=1，表示连接报文成功
			len = MQTT_Subscribe(TxData_Buff,S_TOPIC_NAME,0);  //构建订阅报文
			espconn_sent(pespconn, TxData_Buff, len);          //发送报文
		}else{
			os_printf("CONNECT ERROR!!!\r\n");     //串口输出信息
		}
	}
	//if判断，第一个字节是0x90，表示收到的是SUBACK报文
	//接着我们要判断订阅回复，看看是不是成功
	else if(pusrdata[0]==0x90){
		if((pusrdata[4]==0x00)||(pusrdata[4]==0x01)){	  //判断第5个字节，等于0或1，表示正确
			os_printf("Subscribe Succeeded\r\n");         //串口输出信息
			MQTT_STA = 2;                                 //状态=2，表示订阅成功
			updeta_State();                               //判断开关状态，并发布给服务器
		    os_timer_disarm(&ping_timer);
		    os_timer_setfn(&ping_timer, (os_timer_func_t *)updeta_State, pespconn);      //注册定时器的回调函数
		    os_timer_arm(&ping_timer, 3000, 0);                                      	 //3s定时，非自动模式
		}else{
			os_printf("Subscribe ERROR!!!\r\n");          //串口输出信息
		}
	}
	//if判断，第一个字节是0xD0，表示收到的是PINGRESP报文
	else if(pusrdata[0]==0xD0){
		os_printf("PING OK\r\n"); 		       //串口输出信息
		os_timer_disarm(&ping_timer);
		os_timer_setfn(&ping_timer, (os_timer_func_t *)ping_send, pespconn);      //注册定时器的回调函数
		os_timer_arm(&ping_timer, 3000, 0);                                      //30s定时，非自动模式
	}
	//if判断，如果第一个字节是0x30，表示收到的是服务器发来的推送数据
	//我们要提取控制命令
	else if(pusrdata[0]==0x30){
		os_printf("Server push\r\n"); 		       //串口输出信息
		MQTT_DealPushdata_Qs0(pusrdata,length);    //处理等级0推送数据
	}
}
/*-------------------------------------------------------------*/
/*函数功能：定时发送ping包                                                                                           */
/*参       数：无                                                                                                      */
/*返       回：无                                                                                                     */
/*-------------------------------------------------------------*/
void ICACHE_FLASH_ATTR ping_send(void *arg)
{
	struct espconn *pespconn = arg;

	os_printf("send ping\r\n"); 		     //串口输出信息
	MQTT_PingREQ(TxData_Buff);               //构建ping报文
	espconn_sent(pespconn, TxData_Buff, 2);  //发送ping报文
}
/*-------------------------------------------------*/
/*函数名：判断继电器状态，并发布给服务器            */
/*参  数：无                                       */
/*返回值：无                                       */
/*-------------------------------------------------*/

void ICACHE_FLASH_ATTR updeta_State(void)
{
	char temp[200],switchStat;
	int len;

	if(GPIO_REG_READ(GPIO_OUT_ADDRESS)&0x10)  switchStat = 0;
	else										switchStat = 1;

	os_sprintf(temp,"{\"method\":\"thing.event.property.post\",\"id\":\"1501529882\","
			"\"params\":{\"powerstate\":%d},\"version\":\"1.0.0\"}", switchStat);

	os_printf(temp);
	len = MQTT_PublishQs0(TxData_Buff,P_TOPIC_NAME,temp,os_strlen(temp));       //添加数据，构建报文，发布给服务器
	espconn_sent(&tcpcilent_esp_conn,TxData_Buff, len);                         //发送报文

//    os_timer_disarm(&ping_timer);
//    os_timer_setfn(&ping_timer, (os_timer_func_t *)updeta_State, "");        //注册定时器的回调函数
//    os_timer_arm(&ping_timer, 3000, 0);                                      //3s定时，非自动模式
}
